#ifndef COLORS_H
#define COLORS_H

namespace Cvekas {

/// 32 bit color, A8R8G8B8 format
struct Color : public boost::equality_comparable<Color>, public boost::addable<Color>, 
	public boost::subtractable<Color>, public boost::multipliable<Color>
{
	byte r, g, b, a;

	Color() : r(0), g(0), b(0), a(255) {}
	Color(byte r, byte g, byte b) : r(r), g(g), b(b), a(255) {}
	Color(byte r, byte g, byte b, byte a) : r(r), g(g), b(b), a(a) {}

	Color(int r, int g, int b) : r((byte)r), g((byte)g), b((byte)b), a((byte)255) {}
	Color(int r, int g, int b, int a) : r((byte)r), g((byte)g), b((byte)b), a((byte)a) {}

	Color(DWORD color)
	{
		a = (char)((color & 0xFF000000) >> 24);
		r = (char)((color & 0x00FF0000) >> 16);
		g = (char)((color & 0x0000FF00) >> 8);
		b = (char)((color & 0x000000FF));
	}

	inline const Color& operator=(const Color& c) 
	{ 
		r = c.r; 
		g = c.g;
		b = c.b;
		a = c.a;
		return *this; 
	}

	inline bool operator==(const Color& c) const
	{
		return (r == c.r) && (g == c.g) && (b == c.b) && (a == c.a);
	}

	inline const Color& operator+=(const Color& c) 
	{
		r += c.r; 
		g += c.g;
		b += c.b;
		a += c.a;
		return *this;
	}

	inline const Color& operator-=(const Color& c) 
	{
		r -= c.r; 
		g -= c.g;
		b -= c.b;
		a -= c.a;
		return *this;
	}

	inline const Color& operator*=(const Color& c)
	{
		r = byte(r * c.r / 255); 
		g = byte(g * c.g / 255);
		b = byte(b * c.b / 255);
		a = byte(a * c.a / 255);
		return *this;
	}

	static Color lerp(const Color& c1, const Color& c2, float t)
	{
		Color result;
		result = c1;
		
		result.r += byte(float(c2.r - c1.r) * t);
		result.g += byte(float(c2.g - c1.g) * t);
		result.b += byte(float(c2.b - c1.b) * t);
		result.a += byte(float(c2.a - c1.a) * t);

		return result;
	}

	static Color smoothstep(const Color& c1, const Color& c2, float t)
	{
		if(t < 0.0f)
			return c1;
		if(t > 1.0f)
			return c2;
		return lerp(c1, c2, t * t * (3.0f - 2.0f * t));
	}

	operator D3DCOLOR() const
	{
		return D3DCOLOR_RGBA(r, g, b, a);
	}
};

/// 128 bit floating-point color, values are in range 0.0f -  1.0f
struct ColorF : public D3DXCOLOR
{
	ColorF() : D3DXCOLOR() {}
	ColorF(float r, float g, float b) : D3DXCOLOR(r, g, b, 1.0f) {}
	ColorF(float r, float g, float b, float a) : D3DXCOLOR(r, g, b, a) {}
	ColorF(const Color& color) : D3DXCOLOR((D3DCOLOR)color) {}

	operator Color()
	{
		int r, g, b, a;
		r = (int)(this->r * 255.0f);
		g = (int)(this->g * 255.0f);
		b = (int)(this->b * 255.0f);
		a = (int)(this->a * 255.0f);

		r &= 0xFF;
		g &= 0xFF;
		b &= 0xFF;
		a &= 0xFF;

		return Color(r, g, b, a);
	}
};

} // namespace

#endif